#include "mcmcChangeAtomicRegion.h"
//////////////////////////////////////////////
//////////////////////////////////////////////

// construnction & destruction
MCMC_AtomicRegion_Record::MCMC_AtomicRegion_Record()
{
	indexid_new = 0;
	pmodel = NULL;
}

MCMC_AtomicRegion_Record::~MCMC_AtomicRegion_Record()
{
	Empty();
}

void MCMC_AtomicRegion_Record::Empty(void)
{
	if (pmodel != NULL)
		delete pmodel;
	pmodel = NULL;

	domain.Empty();
}


MCMC_AtomicRegion_Record & MCMC_AtomicRegion_Record::operator=(MCMC_AtomicRegion &a)
{
	// initialization
	Empty();

	if (a.Model() != NULL)
		pmodel = a.Model()->CopyTo();

	domain = a.pixel_set;

	return *this;
}



//////////////////////////////////////////////
//////////////////////////////////////////////

// construction & destruction
MCMC_GRegion_Record::MCMC_GRegion_Record()
{
	indexid_new		= -1;
	pmodel			= NULL;
	pvc_index_table	= NULL;
}

MCMC_GRegion_Record::~MCMC_GRegion_Record()
{
	Empty();
}

void MCMC_GRegion_Record::Empty(void)
{
	if (pmodel != NULL)
		delete pmodel;
	pmodel = NULL;

	list_indexid.Empty();
}


// operators
MCMC_GRegion_Record & MCMC_GRegion_Record::operator=(MCMC_GRegion &a)
{
	Empty();

	if (a.Model() != NULL)
		pmodel = a.Model()->CopyTo();

	assert(pvc_index_table != NULL);

	int indexid1,indexid2;

	indexid1 = a.GetFirstRegion();
	while (indexid1 >= 0)
	{
		indexid2 = pvc_index_table->Data(indexid1);

		list_indexid.Insert(indexid2);
		
		indexid1 = a.GetNextRegion();
	}

	return *this;
}

	
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////

// construction & destruction
MCMC_LayerRegion_Record::MCMC_LayerRegion_Record()
{
	p_aregion_record = NULL;
	num_aregions = 0;

	p_gregion_record = NULL;
	num_gregions = 0;
}

MCMC_LayerRegion_Record::~MCMC_LayerRegion_Record()
{
	Empty();
}
	
void MCMC_LayerRegion_Record::Empty()
{
	if (p_aregion_record != NULL)
		delete []p_aregion_record;
	p_aregion_record = NULL;

	num_aregions = 0;

	if (p_gregion_record != NULL)
		delete []p_gregion_record;
	p_gregion_record = NULL;
	num_gregions = 0;
}
	
	// operator
void MCMC_LayerRegion_Record::Remember(MCMC_Layer_Regions &a)
{
	int i,j,k;
	
	// allocate space
	num_aregions = a.NumAtomicRegions();
	if (num_aregions > 0)
		p_aregion_record = new MCMC_AtomicRegion_Record[num_aregions];

	num_gregions = a.NumGRegions();
	if (num_gregions > 0)
	{
		p_gregion_record = new MCMC_GRegion_Record[num_gregions];
		for (i=0; i<num_gregions; i++)
			p_gregion_record[i].SetIndexTable(vc_index_table);
	}

	// setup the index table
	vc_index_table.SetRowVector(a.MaxGRegionIndex());
	vc_index_table.InitValue(-1);

	MCMC_AtomicRegion	*paregion;
	MCMC_GRegion		*pgregion;
	
	i = 0;
	paregion = a.GetAtomicRegion(a.GetFirstAtomicRegion());
	while (paregion != NULL)
	{
		vc_index_table(paregion->IndexId()) = i++;
		paregion = a.GetAtomicRegion(a.GetNextAtomicRegion());
	}

	pgregion = a.GetGRegion(a.GetFirstGRegion());
	while (pgregion != NULL)
	{
		vc_index_table(pgregion->IndexId()) = i++;
		pgregion = a.GetGRegion(a.GetNextGRegion());
	}

	MCMC_AtomicRegion_Record *pa_record;
	MCMC_GRegion_Record		 *pg_record;
	bool bgo;

	// the old partition map
	ras_partition_map_old.SetDimension(a.height, a.width);
	
	// to backup
	paregion = a.GetAtomicRegion(a.GetFirstAtomicRegion());
	while (paregion != NULL)
	{
		k = Id4IndexId(paregion->IndexId());
		pa_record = GetARegionRecord(k);
		assert(pa_record != NULL);
		*pa_record = *paregion;
		
		bgo = paregion->GetFirstPixel(j, i);
		while (bgo)
		{
			ras_partition_map_old(j, i) = k;
			bgo = paregion->GetNextPixel(j, i);
		}
		
		paregion = a.GetAtomicRegion(a.GetNextAtomicRegion());
	}

	pgregion = a.GetGRegion(a.GetFirstGRegion());
	while (pgregion != NULL)
	{
		k = Id4IndexId(pgregion->IndexId());
		pg_record = GetGRegionRecord(k);
		*pg_record = *pgregion;

		pgregion = a.GetGRegion(a.GetNextGRegion());
	}
}

void MCMC_LayerRegion_Record::WhoTakesMost(LinkList<int> *p_lists, MCMC_Layer_Regions &a)
{
	mcmcVector<int>	vc_num;
	MCMC_AtomicRegion *paregion;
	bool	bgo;
	int		i,j,k;
	int	lmax;

	vc_num.SetRowVector(num_aregions);
	vc_num.InitValue(0);

	paregion = a.GetAtomicRegion(a.GetFirstAtomicRegion());
	while (paregion != NULL)
	{
		// find out which old atomic region has the most part of this one
		bgo = paregion->GetFirstPixel(j, i);
		while (bgo)
		{
			vc_num(ras_partition_map_old(j, i))++;

			bgo = paregion->GetNextPixel(j, i);
		}
		
		k = -1;
		lmax = 0;
		for (i=0; i<vc_num.size(); i++)
		{
			if (vc_num(i) > lmax)
			{
				lmax = vc_num(i);
				k = i;
			}
			vc_num(i) = 0;
		}

		assert(k>=0);
		p_lists[k].Insert(paregion->Id());

		paregion = a.GetAtomicRegion(a.GetNextAtomicRegion());
	}

}


void MCMC_LayerRegion_Record::Recover(MCMC_Layer_Regions &a)
{
	int				id_gregion;
	LinkList<int>	list_gregions;
	bool			bgo;

	// initialization
	vc_aregion_sign.SetRowVector(a.MaxAtomicRegionSpace());
	vc_aregion_sign.InitValue(0);

	// get all the gregion in a
	id_gregion = a.GetFirstGRegion();
	while (id_gregion >= 0)
	{
		list_gregions.Insert(id_gregion);
		id_gregion = a.GetNextGRegion();
	}
	
	// delete all the g-region
	bgo = list_gregions.GetFirst(id_gregion);
	while (bgo)
	{
		a.DeleteGRegion(id_gregion);
		bgo = list_gregions.GetNext(id_gregion);
	}
	
	// create g-regions
	int				i,j;
	MCMC_GRegion	*pgregion;
	MCMC_AtomicRegion_Record *pa_record;
	MCMC_GRegion_Record		 *pg_record;

	for (i=0; i<num_gregions; i++)
	{
		pgregion = a.GetGRegion(a.NewGRegion());
		assert(pgregion != NULL);
		pgregion->SetStat(p_gregion_record[i].Model());

		p_gregion_record[i].SetNewIndexId(pgregion->IndexId());
	}

	LinkList<int> *p_lists;
	
	p_lists = new LinkList<int>[num_aregions];

	WhoTakesMost(p_lists, a);

	MCMC_GRegion	*pgregion2;
	MCMC_AtomicRegion *paregion;
	bool	bgo2;
	int		id_aregion;

	// create relations
	for (i=0; i<num_gregions; i++)
	{
		pgregion = (MCMC_GRegion*) a.GetRegionFromIndexId(p_gregion_record[i].IndexIdNew());
		assert(pgregion != NULL);
		
		bgo = p_gregion_record[i].GetFirstChild(j);
		while (bgo)
		{
			if (IsAtomic(j))
			{
				pa_record = GetARegionRecord(j);
				assert(pa_record != NULL);
				
				bgo2 = p_lists[j].GetFirst(id_aregion);
				while (bgo2)
				{
					paregion = a.GetAtomicRegion(id_aregion);
					assert(paregion != NULL);

					pgregion->AddRegion(paregion->IndexId());
					paregion->SetIndexIdParent(pgregion->IndexId());
					
					bgo2 = p_lists[j].GetNext(id_aregion);
				}
				
			}
			else
			{
				pg_record = GetGRegionRecord(j);
				assert(pg_record != NULL);
				
				pgregion2 = (MCMC_GRegion*) a.GetRegionFromIndexId(pg_record->IndexIdNew());
				assert(pgregion2 != NULL);

				// establish the parent-child relation
				pgregion->AddRegion(pgregion2->IndexId());
				pgregion2->SetIndexIdParent(pgregion->IndexId());
			}
			bgo = p_gregion_record[i].GetNextChild(j);
		}
	}
	
	if (p_lists != NULL)
		delete []p_lists;
	p_lists = NULL;
	
	a.DeleteAllEmptyGRegions();
}


bool MCMC_LayerRegion_Record::RePartitionAtomicRegions(MCMC_Layer_Regions &layer_region, Raster<int> &ras_label_map)
{
	// remember the old structure
	Remember(layer_region);

	// relable the partition map
	int					i,j,k;
	MCMC_AtomicRegion	*paregion;
	bool				bgo;
	
	ras_partition_map_new.SetDimension(ras_label_map.rows(), ras_label_map.cols());

	// label the current atomic regions
	k = 1;
	paregion = layer_region.GetAtomicRegion(layer_region.GetFirstAtomicRegion());
	while (paregion != NULL)
	{
		bgo = paregion->GetFirstPixel(j, i);
		while (bgo)
		{
			ras_partition_map_new(j, i) = (k-1)*num_aregions+ras_label_map(j, i);

			bgo = paregion->GetNextPixel(j, i);
		}
		k++;

		paregion = layer_region.GetAtomicRegion(layer_region.GetNextAtomicRegion());
	}
	
	ras_partition_map_new.RelabelReorder();
	ras_partition_map_new.Relabel(false);
	int num=ras_partition_map_new.RelabelAndMergeTinyRegions(13);
	if (num > layer_region.MaxAtomicRegionSpace()-100)
		return false;

	// build a new graph

	// free all space
	layer_region.InitilizeAllMembers();
	layer_region.Build(ras_partition_map_new);
	
	paregion = layer_region.GetAtomicRegion(layer_region.GetFirstAtomicRegion());
	while (paregion != NULL)
	{
		paregion->CreateRegionDomain();
		paregion->LabelFromDomain(ras_partition_map_new, paregion->Id());

		paregion = layer_region.GetAtomicRegion(layer_region.GetNextAtomicRegion());
	}
	
	// reconver the structure
	Recover(layer_region);

	layer_region.MergeSmallAtomicRegion(5);
	layer_region.CleanTopologyForGRegions();
	
	layer_region.ReGenerateNbRelationships();
	layer_region.CreateTopologyRecords();
	
	
	return true;
}

///////////////////////////////////////////
// to split individual atomic regions

bool MCMC_LayerRegion_Record::RePartitionAtomicRegions(LinkList<int> &list_new_aregions, MCMC_Layer_Regions &layer_region, 
													   LinkList<int> &list_aregion_tochange, Raster<int> &ras_label_map)
{
	// prepare label map
	ras_partition_map_new.SetDimension(ras_label_map.rows(), ras_label_map.cols());
	ras_partition_map_new.InitValue(0);

	// reset the label
	bool				bgo,bgo2;
	int					id_aregion,i,j,k;
	MCMC_AtomicRegion	*paregion;
	Raster<int>			ras_temp;
	irmm_Rect			bound;

	bound.Set(9999,9999,-9999,-9999);
	
	bgo = list_aregion_tochange.GetFirst(id_aregion);
	while (bgo)
	{
		paregion = layer_region.GetAtomicRegion(id_aregion);
		assert(paregion!=NULL);
		
		bgo2 = paregion->GetFirstPixel(j, i);
		while (bgo2)
		{
			bound.SetBound(i, j);
			bgo2 = paregion->GetNextPixel(j, i);
		}

		bgo = list_aregion_tochange.GetNext(id_aregion);
	}
	if (!bound.ValidBound())
		return false;
	
	ras_temp.SetDimension(bound.Height(), bound.Width());
	ras_temp.InitValue(0);

	k = 1;
	bgo = list_aregion_tochange.GetFirst(id_aregion);
	while (bgo)
	{
		paregion = layer_region.GetAtomicRegion(id_aregion);
		assert(paregion!=NULL);
		
		bgo2 = paregion->GetFirstPixel(j, i);
		while (bgo2)
		{
			ras_temp(j-bound.top, i-bound.left) = (ras_label_map(j,i)-1)*list_aregion_tochange.Num()+k;

			bgo2 = paregion->GetNextPixel(j, i);
		}

		k++;
		bgo = list_aregion_tochange.GetNext(id_aregion);
	}
	
	int			label_min,label_max,label_temp;
	mcmcVector<int> vc_id_new;
	MCMC_AtomicRegion *paregion_new;
	MCMC_GRegion	*pgregion;
	MCMC_PixelSet	domain_temp;
	LinkList<int>	list_temp;

	ras_temp.RelabelReorder(1);
	ras_temp.RelabelAndMergeTinyRegions(5);

	// split the region one by one
	bgo = list_aregion_tochange.GetFirst(id_aregion);
	while (bgo)
	{
		paregion = layer_region.GetAtomicRegion(id_aregion);
		assert(paregion!=NULL);
		pgregion = (MCMC_GRegion*) layer_region.GetRegionFromIndexId(paregion->IndexIdParent());
		if (pgregion != NULL)
			pgregion->DeleteRegion(paregion->IndexId());
		
		label_min = 9999;
		label_max = -9999;

		domain_temp = paregion->pixel_set;

		// copy the label map
		bgo2 = domain_temp.GetFirst(j, i);
		while (bgo2)
		{
			label_temp = ras_temp(j-bound.top, i-bound.left);
			if (label_temp > label_max)
				label_max = label_temp;
			if (label_temp < label_min)
				label_min = label_temp;

			bgo2 = domain_temp.GetNext(j, i);
		}
		if (label_max-label_min > 0)
		{
			// change the label
			bgo2 = paregion->GetFirstPixel(j, i);
			while (bgo2)
			{
				label_temp = ras_temp(j-bound.top, i-bound.left);
				ras_partition_map_new(j, i) = (label_temp-label_min+1);

				bgo2 = paregion->GetNextPixel(j, i);
			}
		
			vc_id_new.SetRowVector(label_max-label_min+1);
			vc_id_new.InitValue(-1);

			layer_region.Build(ras_partition_map_new, label_max-label_min+1, paregion, &vc_id_new, false);
			for (i=0; i<vc_id_new.size(); i++)
			{
				paregion_new = layer_region.GetAtomicRegion(vc_id_new(i));
				if (pgregion!=NULL && paregion_new!=NULL && paregion_new->Valid())
				{
					paregion_new->SetIndexIdParent(pgregion->IndexId());
					if (pgregion != NULL)
						pgregion->AddRegion(paregion_new->IndexId());
					list_temp.Insert(paregion_new->Id());
				}
			}

			layer_region.DeleteNoValidRegion();
			
			bgo2 = domain_temp.GetFirst(j, i);
			while (bgo2)
			{
				ras_partition_map_new(j, i) = 0;

				bgo2 = domain_temp.GetNext(j, i);
			}
		}
		else
			list_temp.Insert(paregion->Id());

		bgo = list_aregion_tochange.GetNext(id_aregion);
	}
	
	layer_region.SetHoleRelationship();
	layer_region.MergeSmallAtomicRegion(5);

	layer_region.ReGenerateNbRelationships();
	layer_region.CreateTopologyRecords();
	
	// get created new regions
	list_new_aregions.Empty();
	bgo = list_temp.GetFirst(id_aregion);
	while (bgo)
	{
		paregion = layer_region.GetAtomicRegion(id_aregion);
		if (paregion!=NULL && paregion->Valid())
			list_new_aregions.Insert_unique(paregion->Id());

		bgo = list_temp.GetNext(id_aregion);
	}
	
	return true;
}

